﻿using LightCAD.Core.Elements;
using LightCAD.Three;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.Model
{
    public  class TransformAction
    {
        protected DocumentRuntime docRt;
        protected IDocumentEditor docEditor;
        protected CommandCenter commandCenter;
        protected ICommandControl commandCtrl;
        protected Model3DEditRuntime model3dRuntime;
        protected Snap3dRuntime snap3dRuntime;
        public TransformAction(IDocumentEditor docEditor)
        {
            this.docEditor = docEditor;
            this.docRt = docEditor.DocRt;
            this.commandCenter = this.docEditor.CommandCenter;
            this.commandCtrl = this.commandCenter.Commander;
            this.model3dRuntime = docEditor as Model3DEditRuntime;
            this.snap3dRuntime = this.model3dRuntime.Snap3DRuntime;
        }
        /// <summary>
        /// 平移
        /// </summary>
        public async void MoveTransform(string[] args) 
        {
            Vector3 basePoint = null;
            Vector3 targetPoint = null;
            ListEx<IElement3d> selEles = null;
            ListEx<Vector3> selElePositions = null;
            ListEx<Plane> snapPlanes = null;
            var eleInputer = new EleInputer3d(this.docEditor);
            var pinputer = new PointInputer3d(this.docEditor);
            void onMouseEvent(string name, MouseEventRuntime mer)
            {
                if (name == "Move")
                {
                    if (basePoint != null && targetPoint == null)
                    {
                        var movePoint = snap3dRuntime.SnapPoint;
                        Move(basePoint,movePoint);
                    }
                }
            }
            void Move(Vector3 start, Vector3 target)
            {
                if (start != target)
                {
                    var offset = target - start;
                    for (int i = 0; i < selEles.Count; i++)
                    {
                        var solid = selEles[i] as LcComponentInstance;
                        solid.Position.AddVectors(selElePositions[i], offset);
                        solid.UpdateTransformMatrix();
                    }
                }
            }
            selEles = docRt.Action.SelectedElements.Where(s => s is LcComponentInstance).Cast<IElement3d>().ToListEx();
            StartAction();
            if (selEles.Count > 0)
                goto step1;
        step0:
            var eleResult = await eleInputer.Execute("选择元素");
            if (eleResult == null)
                goto step0;
            if (eleResult.IsCancelled)
                goto cancel;
            selEles = (eleResult.ValueX as ListEx<IElement3d>);
        step1:
            selElePositions = selEles.Where(n=>n is LcComponentInstance).Select(e => (e as LcComponentInstance).Position.Clone()).ToListEx();
            var presult = await pinputer.Execute("选择基点");
            if (presult == null)
                goto cancel;
            if (presult.IsCancelled)
                goto cancel;
            basePoint = presult.ValueX as Vector3;
        step2:
            snapPlanes = new ListEx<Plane> {
                    new Plane().SetFromNormalAndCoplanarPoint(Vector3.ZAxis,basePoint.Clone()),
                    new Plane().SetFromNormalAndCoplanarPoint(snap3dRuntime.GetCameraDir().Negate(),basePoint.Clone())
                };
            this.model3dRuntime.EnableCameraControl(false);
            this.snap3dRuntime.AddIgnorEles(selEles);
            this.snap3dRuntime.AddSnapPlanes(snapPlanes);
            this.model3dRuntime.Control.AttachEvents(null, null, onMouseEvent, null, null, null, null);
            presult = await pinputer.Execute("移动中...");
            this.model3dRuntime.Control.DetachEvents(null, null, onMouseEvent, null, null, null, null);
            this.snap3dRuntime.ClearSnapPlanes(snapPlanes);
            this.snap3dRuntime.ClearIgnorEles(selEles);
            this.model3dRuntime.EnableCameraControl(true);
            if (presult == null|| presult.IsCancelled)
                goto cancel;
            targetPoint = presult.ValueX as Vector3;
            Move(basePoint, targetPoint);
            goto end;
        cancel:
            if (selEles.Count > 0)
                for (int i = 0; i < selEles.Count; i++)
                {
                    var solid = selEles[i] as LcComponentInstance;
                    solid.Position.Copy(selElePositions[i]);
                }
        end:
            this.commandCtrl.WriteInfo("移动完成！");
            this.commandCtrl.SetInputText("");
            EndAction();
           
        }
        public async void RotateTransform(string[] args) 
        {
        }

        private void StartAction()
        {
            this.docEditor.CommandCenter.InAction = true;
        }
        private void EndAction() 
        {
            this.commandCtrl.Prompt(string.Empty);
           
            this.commandCtrl.SetCurMethod(null);
            this.commandCtrl.SetCurStep(null);
            this.docEditor.CommandCenter.InAction = false;
        }
    }
}
